<?php

/**
 * @param $hexString  $str = '620300000002';
 * @return string 返回2进制字符串
 */
if (!function_exists('strToBinary')) {
    function strToBinary($hexString): string
    {
        $binaryString = '';
        // 按每两个字符分割原始字符串
        $bytes = str_split($hexString, 2);
        foreach ($bytes as $byte) {
            $binaryString .= chr(hexdec($byte)); // 将16进制转化为10进制，再通过chr函数，把输入的10进制数字转化为对应的ascii字符，该字符实际上是2进制字符
        }
        return $binaryString;
    }
}

/**
 * @param $data 输入的是2进制字符串， 如$data = "\x62\x03\x00\x00\x00\x02";
 * @return string
 */
if (!function_exists('calculateModbusCRC')) {
    function calculateModbusCRC($data): string
    {
        // $data = "\x62\x03\x00\x00\x00\x02"; // 模拟输入条件,输入的值是二进制字符串或者称之为字节字符串， 此处strlen($data) = 6
        $crc = 0xFFFF;
        for ($i = 0; $i < strlen($data); $i++) {
            $crc ^= ord($data[$i]); // ord函数将每个16进制表示（00-Ff）的单个字符，返回其ascii值 （如 \x62 返回 int 98）
            for ($j = 0; $j < 8; $j++) {
                if ($crc & 0x0001) {
                    $crc = ($crc >> 1) ^ 0xA001; // crc多项式
                } else {
                    $crc >>= 1;
                }
            }
        }
        // 最终返回的crc是一个int整数
        $strB = pack('v', $crc); // 2进制字符串通常不能直接echo或者var_dump，除非少部分具有ascii码的字母按键，而且这也没有实际的意义, 经过pack函数重新把其打印成2进制的字符串， v表示无符号的长整形（32位，小端字节序）
        $str = bin2hex($strB); // 把2进制的字符串转为16进制
        return strtoupper($str);
    }
}
